package com.swotxu.oldwebproject.redis.listener;

import com.swotxu.oldwebproject.redis.RedisManager;
import com.swotxu.oldwebproject.redis.connection.IRedisConnection;
import com.swotxu.oldwebproject.session.utils.RedisServletContext;
import com.swotxu.oldwebproject.session.utils.RedisSessionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.JedisPubSub;

/**
 * redis监听器
 * 监听 redisSession 的 del 和 expired 事件
 * 用于响应用户退出下线
 *
 * @Date: 2020/1/16 10:33
 * @Author: xu.hai
 */
public class UserRedisSessionListener extends JedisPubSub {
    private static final Logger LOGGER = LoggerFactory.getLogger(UserRedisSessionListener.class);
    private static final String LOCK_KEY = RedisSessionUtil.SERVLETCONTEXT + "lock.";
    private static final int LOCK_WAIT = 3;
    private static IRedisConnection connection = RedisManager.getIRedisConnection();

    // 取得订阅的消息后的处理
    @Override
    public void onMessage(String s, String s1) {
    }

    /**
     * 取得按表达式的方式订阅的消息后的处理
     *   -- 在项目集群环境下，key失效或删除，会触发多个监听器，为避免重复处理，需添加分布式锁
     *
     * @param pattern
     * @param channel
     * @param key   如：cbm:session:E698C25631C80C5DE7B41B1D24FD968E
     */
    @Override
    public void onPMessage(String pattern, String channel, String key) {
        if (!key.contains(RedisSessionUtil.SESSION_PREFIX)) {
            LOGGER.debug("Not is redis session key!");
        } else {
            LOGGER.info(String.format("pattern: %s, channel: %s, key: %s", pattern, channel, key));
            // 1.设置 sessionid 对应锁，lockKey = cbm:servletContext:lock.E698C25631C80C5DE7B41B1D24FD968E
            String sessionId = key.substring(RedisSessionUtil.SESSION_PREFIX.length());
            String lockKey = LOCK_KEY + sessionId;
            Object lock = connection.getSet(lockKey, 1);
            LOGGER.info(String.format("lock: %s, getSet: %d, trylock: %b", lockKey, lock, lock == null));

            // 2.设置锁 3s后自动过期 -- 自动释放锁
            connection.expire(lockKey, LOCK_WAIT);

            // 3.用户下线处理
            if (lock == null) {
                RedisServletContext.logoutAndRecord(sessionId);
            } else {
                LOGGER.info("The current event has been processed by another listener!");
            }
        }
    }
    // 初始化订阅时的处理
    @Override
    public void onSubscribe(String s, int i) {
    }
    // 取消订阅时的处理
    @Override
    public void onUnsubscribe(String s, int i) {
    }
    // 取消按表达式的方式订阅时的处理
    @Override
    public void onPUnsubscribe(String s, int i) {
    }
    // 初始化按表达式的方式订阅时的处理
    @Override
    public void onPSubscribe(String s, int i) {
        LOGGER.debug(String.format("[redisListener onPSubscribe] -> s: %s, i: %d", s, i));
    }
}
